package procsim;

public class MMultiplexer implements Element{
    private MSignal inSig[], result, cSigM;
    private Signal cSig[];
    private Signal enable = new Signal(1);
    protected int inNum;
    private int cNum, numOfBits;
    private int inP=0, cP=0;
    protected boolean enableNotSet = true;
    protected String name = "MP";
    public MMultiplexer(int nob, int num){
        numOfBits=nob;
        inNum=Util.roundToNextMultiple(num); // zaokruzivanje na sledeci stepen dvojke
        cNum=(int)Math.getExponent(inNum); // broj kontrolnih signala je ld(inNum)
        inSig=new MSignal[inNum];
        cSig=new Signal[cNum];
        result=new MSignal(numOfBits, 0);
    }
    public MMultiplexer(int nob, int number, MSignal in[], Signal control[]){
        this(nob, number);
        for(int i=0; i<inNum; i++, inP++){
            if(in[i]!=null) in[i].addElement(this);
            inSig[i]=in[i];
        }
        for(int i=0; i<cNum; i++, cP++){
            if(control[i]!=null) control[i].addElement(this);
            cSig[i]=control[i];
        }
    }
    public MMultiplexer(int nob, int number, MSignal in[], MSignal control){
        this(nob, number);
        for(int i=0; i<inNum; i++, inP++){
            if(in[i]!=null) in[i].addElement(this);
            inSig[i]=in[i];
        }
        if(control!=null) control.addElement(this);
        cSigM=control;
    }
    public MMultiplexer addIn(MSignal s){
        if(inP<inNum){
            if(s!=null) s.addElement(this);
            inSig[inP++]=s;
        }
        else
            System.err.println("Nema vise mesta za nove signale");
        return this;
    }
    public MMultiplexer addControl(Signal sig){
        if(cSigM!=null) // Ne mesamo babe i zabe
            System.err.println("Ne mogu se dodati novi signali");
        else if(cP<cNum){
            if(sig!=null) sig.addElement(this);
            cSig[cP++]=sig;
        }
        else
            System.err.println("Nema vise mesta za nove signale");
        return this;
    }
    public MMultiplexer setResult(MSignal sig){
        result=sig;
        return this;
    }
    public MMultiplexer setEnableBit(Signal sig){
        if(enable!=null) enable.addElement(this);
        enable = sig;
        enableNotSet = false;
        return this;
    }
    public void setName(String name){
        this.name = name;
    }
    @Override
    public MMultiplexer tick(){
        if(enable!=null && enable.isNull()){
            result.set(0);
            return this;
        }
        Signal[] sigarray;
        if(cSigM==null)
            sigarray=cSig;
        else
            sigarray=cSigM.getBits();
        if(result!=null) result.set(inSig[Util.binaryArray2Int(Util.signalArray2IntArray(sigarray))]);
        return this;
    }
    @Override
    public MSignal result() {
        return result;
    }
    @Override
    public String toString(){
        return ""+result();
    }
    @Override
    public void updateSignal(Sig sig) { // proveriti i testirati!
        boolean changed = false;
        if(cSigM!=null && cSigM==sig){
            cSigM.set(sig.get(), false);
            changed = true;
        }
        if(enable!=null && enable==sig){
            enable.set(sig.get(), false);
            changed = true;
        }
        for(int i=0; i<inSig.length; i++){
            if(inSig[i]!=null && inSig[i]==sig){
                inSig[i].set(sig.get(), false);
                changed = true;
            }
        }
        for(int i=0; i<cSig.length; i++){
            if(cSig[i]!=null && cSig[i]==sig){
                cSig[i].set(sig.get(), false);
                changed = true;
            }
        }
        if(changed) tick();
    }
}
